import axios from 'axios'
const instance = axios.create({
  baseURL: 'http://127.0.0.1:4523/m1/5898866-5585714-default', //请求的基础地址
  // baseURL: 'https://jra.jd.com/jsTk.do', //请求的基础地址
  timeout: 2000, //默认请求时间两秒
  withCredentials: false, //表示跨域请求时是否需要使用凭证
})
let errornum = 0 //错误次数
const timeoutArr: number[] = []
// 添加请求拦截器
instance.interceptors.request.use(
  (config) => {
    // 在发送请求之前做些什么
    // 接口响应慢时设置异常提醒，超过设置时间接口未响应则弹窗
    // if (dsf.config.login.ajaxWaitTime && !timeoutArr[config.url]) {
    //   timeoutArr[config.url] = setTimeout(() => {
    //     dsf.layer.alert({
    //       title: '温馨提示',
    //       message: dsf.config.login.ajaxWaitReminder || '网络存在异常，请耐心等待',
    //     })
    //   }, dsf.config.login.ajaxWaitTime)
    // }
    return config
  },
  (error) => {
    // 对请求错误做些什么
    return Promise.reject(error)
  },
)

// 添加响应拦截器
instance.interceptors.response.use(
  (response) => {
    /**
     * 如果您想要获取诸如头或状态之类的http信息
     * 就 return  response => response
     */
    // 对响应数据做点什么
    // const res = response.data;
    // 响应清空时间器
    // if (timeoutArr[response.config.url]) {
    //   clearTimeout(timeoutArr[response.config.url])
    // }
    // if (res.status === 501) {
    //   dsf.layer.toast("操作被取消，暂时不能操作");
    // }
    return response
  },
  (error) => {
    // 对响应错误做点什么
    // errornum++;
    if (error.response) {
      console.log(error.response)
      const res = error.response
      if (timeoutArr[res.config.url]) {
        clearTimeout(timeoutArr[res.config.url])
      }
      if (res.status === 401) {
        error.message = ''
        if (errornum == 1) {
          //只提示一次
          // if (store.getClientName() == "app" || store.getClientName() == "browser") { //app内或者浏览器访问  都返回登录页
          //   dsf.layer.toast("您进行了未授权的访问,请重新登录！", undefined, function () {
          //     errornum = 0;
          //     store.logOut();
          //   });
          // } else {
          //   dsf.layer.toast("您进行了未授权的访问,请重新登录！", undefined, function () {
          //     errornum = 0;
          //   });
          //   //store.logOut();
          // }
        }
      } else if (res.status === 400) {
        console.log('客户端错误！' + res.status)
      } else if (res.status === 403) {
        // dsf.layer.toast("您的权限不足,请联系管理员！" + res.status);
      } else if (res.status === 404) {
        console.log('网络请求不存在,请联系管理员！' + res.status)
      } else if (res.status === 500) {
        console.log('服务器异常,请稍后重试！' + res.status)
      } else if (res.status === 501) {
        console.log('您的操作被取消或不允许提交！' + res.status)
      } else if (res.status === 504) {
        console.log('网络错误,请联系管理员！' + res.status)
      } else {
        // dsf.layer.toast("服务器正在开小差。。。。" + res.status);
      }
    } else if (error.message.includes('timeout')) {
      if (errornum == 1) {
        //只提示一次
        // dsf.layer.toast("请求超时，请检查网络连接！", undefined, function () {
        //   errornum = 0;
        // });
      }
    }
    return Promise.reject(error)
  },
)
// 修改url地址
function getWebPath(url: string) {
  if (!url) {
    return ''
  }
  if (url.indexOf('/') == 0) {
    url = url.substring(1)
  } else if (url.indexOf('.') == 0 || url.indexOf('http://') == 0 || url.indexOf('https://') == 0) {
    return url
  }
  if (url.indexOf('public') == 0) {
    if (import.meta.env.MODE === 'development') {
      return location.origin + '/' + url
    } else {
      return '../' + 'dist/' + url
    }
  }

  /*
  如果是开发环境就读取dsf.config.webRoot,因为开发环境走代理，接口在远程服务器
  如果是生产环境直接../拼上url即可，支持在DreamMobile中和DreamWeb中部署移动端dist
  
  */
  if (import.meta.env.MODE === 'development') {
    // return dsf.config.webRoot + url
    return url
  } else {
    return '../' + url
  }
}
//自定义get请求
function get(url: string, params?: any, config?: any) {
  url = getWebPath(url)
  let option = {
    params,
  }
  // 设定token怎么传递
  // if (store.loadSessionStore("loginToken")) {
  //   opts.headers["x-auth-token"] = store.loadSessionStore("loginToken");
  // }
  option = Object.assign(option, config || {})
  return instance.get(url, option)
}
// 不走自定义get请求
function getNoRootUrl(url: string, params?: any, config?: any) {
  url = getWebPath(url)
  let option = {
    params,
  }
  option = Object.assign(option, config || {})
  return axios.get(url, option)
}
// 不走自定义post请求
function postNoRootUrl(url: string, data?: any, config?: any) {
  url = getWebPath(url)
  let option = {
    data,
  }
  option = Object.assign(option, config || {})
  return axios.post(url, option)
}
//自定义post请求
function post(url: string, data?: any, config?: any) {
  url = getWebPath(url)

  let option = {
    data,
    // headers: {
    //   "Content-Type": "application/json"
    // },
  }
  // 设定token怎么传递
  // if (store.loadSessionStore("loginToken")) {
  //   opts.headers["x-auth-token"] = store.loadSessionStore("loginToken");
  // }
  option = Object.assign(option, config || {})
  return instance.post(url, option)
}

// 文件上传
function upload(url: string, file: any, params?: any, config?: any) {
  if (file.size === 0) {
    // dsf.layer.toast(`不允许上传空文件`, false);
    return
  }
  let options = {
    headers: {
      'Content-Type': 'multipart/form-data',
    },
  }
  // if (store.loadSessionStore("loginToken")) {
  //   opts.headers["x-auth-token"] = store.loadSessionStore("loginToken");
  // }
  options = Object.assign(options, config || {})
  let forms = new FormData()
  forms.append('file', file)
  for (let k in params) {
    forms.append(k, params[k])
  }
  url = getWebPath(url)
  return instance.post(url, forms, options)
}
//大文件上传
function bigUpload(url: string, file: any, params?: any, config?: any) {
  if (file.size === 0) {
    // dsf.layer.toast(`不允许上传空文件`, false);
    return
  }
  let options = {
    headers: {
      'Content-Type': 'multipart/form-data',
    },
  }
  // if (store.loadSessionStore("loginToken")) {
  //   opts.headers["x-auth-token"] = store.loadSessionStore("loginToken");
  // }

  // 读取并上传分片
  const chunkSize = 1024 * 1024 * 5 // 5MB
  const totalChunks: any = Math.ceil(file.size / chunkSize) // 总分片数
  let currentChunk: any = 0 // 当前上传的分片
  async function uploadChunk(start: number, end: number) {
    const chunk = file.slice(start, end)
    const formData = new FormData()
    formData.append('file', chunk)
    formData.append('chunk', currentChunk)
    formData.append('chunks', totalChunks)

    // 发送POST请求上传分片
    options = Object.assign(options, config || {})
    url = getWebPath(url)
    return await instance
      .post(url, formData, options)
      .then((response: any) => response.json())
      .then((data) => {
        if (data.success) {
          // 继续上传下一个分片
          currentChunk++
          if (currentChunk < totalChunks) {
            const start = currentChunk * chunkSize
            const end = start + chunkSize
            uploadChunk(start, end)
          } else {
            console.log('文件上传完成')
          }
        } else {
          console.log('上传失败')
        }
      })
      .catch((error) => {
        console.error('上传出错', error)
      })
  }
  // 开始上传第一个分片
  const start = currentChunk * chunkSize
  const end = start + chunkSize
  return uploadChunk(start, end)
}

// 封装请求队列
// 创建取消标记
const source = axios.CancelToken.source()
class RequestQueue {
  queue: any[]
  maxConcurrentRequests: number
  activeRequests: Map<any, any>
  retryDelayBase: number
  maxRetries: number
  constructor(maxConcurrentRequests = 5, maxRetries = 3) {
    this.queue = []
    this.maxConcurrentRequests = maxConcurrentRequests
    this.activeRequests = new Map() //new Map() 使用Map来跟踪activeRequests，便于取消
    this.retryDelayBase = 1000 // 重试基础延迟（毫秒）
    this.maxRetries = maxRetries // 最大重试次数
  }

  // 添加请求到队列
  enqueue(requestPromise: any, requestId = '', priority = 0, shouldRetry = true) {
    if (this.hasRequest(requestId)) {
      console.warn(`Request with ID ${requestId} already exists in the queue.`)
      return Promise.resolve(null)
    }
    // const controller = new AbortController();
    // const signal = controller.signal;
    // const requestPromise = requestPromiseCreator(signal); // 假设requestPromiseCreator接受一个AbortSignal
    // const requestPromise = requestPromiseCreator(source.token); // 假设requestPromiseCreator接受一个AbortSignal
    return new Promise((resolve, reject) => {
      this.queue.push({
        requestPromiseCreator: () =>
          requestPromise.catch((error: any) => {
            if (!shouldRetry || !(error instanceof DOMException) || error.name !== 'AbortError') {
              throw error // 如果不是AbortError且不应重试，则直接抛出错误
            }
          }),
        resolve,
        reject,
        requestId,
        priority,
        status: 'pending',
        retries: 0,
        // controller, // 存储AbortController以便可以取消请求
      })

      // 根据优先级对队列进行排序（高优先级先处理）
      this.queue.sort((a, b) => b.priority - a.priority)

      this.processQueue()
    })
  }

  // 处理队列中的请求
  async processQueue() {
    if (this.activeRequests.size >= this.maxConcurrentRequests || this.queue.length === 0) {
      return
    }

    const nextRequest = this.queue.shift()
    nextRequest.status = 'in_progress'
    // this.activeRequests++;
    // 在Map中存储当前活动的请求，以便可以取消
    this.activeRequests.set(nextRequest.requestId, nextRequest)
    try {
      const result = await nextRequest.requestPromiseCreator()
      nextRequest.resolve(result)
      nextRequest.status = 'completed'
    } catch (error) {
      if (nextRequest.retries < this.maxRetries) {
        nextRequest.retries++
        const delay = this.retryDelayBase * Math.pow(2, nextRequest.retries - 1) // 指数退避策略
        console.warn(`Retrying request ${nextRequest.requestId} after ${delay}ms delay.`)
        setTimeout(() => this.processQueue(), delay) // 延迟后重试（注意：这可能导致顺序问题，需要更复杂的逻辑来处理）
      } else {
        nextRequest.reject(error)
        nextRequest.status = 'failed'
      }
    } finally {
      // this.activeRequests--;
      this.activeRequests.delete(nextRequest.requestId) // 无论成功还是失败，都从活动请求中移除
      this.processQueue() // 递归处理下一个请求
    }
  }

  // 检查队列中是否有某个请求（用于去重）
  hasRequest(requestId: string) {
    return this.queue.some((req) => req.requestId === requestId)
  }
  // 取消请求
  cancelRequest(requestId: string, mes?: string) {
    const request = this.activeRequests.get(requestId)
    if (request) {
      // request.controller.abort(); // 取消请求
      source.cancel(mes || '请求取消的原因') // 取消请求
      // 可选：从队列中移除（如果它还在队列中等待）
      this.queue = this.queue.filter((req) => req.requestId !== requestId)
      // 注意：由于请求已经在处理中，我们不需要从activeRequests中移除它，因为finally块会处理
    } else {
      console.warn(`No active request found with ID ${requestId} to cancel.`)
    }
  }
  // 可选：添加方法来查询请求状态（基于 requestId）
  getRequestStatus(requestId: string) {
    const request =
      this.queue.find((req) => req.requestId === requestId) || this.activeRequests.get(requestId)
    return request ? request.status : 'not_found'
  }
}
// 创建请求队列实例
function createRequestQueue(
  urls: any[] = [],
  maxConcurrentRequests: number = 1,
  maxRetries: number = 1,
) {
  const requestQueue = new RequestQueue(maxConcurrentRequests, maxRetries)
  urls = urls || []
  return Promise.all(
    urls.map((item) => {
      if (item.cancel) {
        setTimeout(() => {
          requestQueue.cancelRequest(item.id, item.cancelMes || '请求取消的原因') // 取消请求
        }, item.timer || 3000)
      }
      return requestQueue.enqueue(post(item.url, item.params || {}, { cancelToken: source.token }))
    }),
  )
}
export { post, upload, postNoRootUrl, get, getNoRootUrl, instance, createRequestQueue, bigUpload }
